package com.fkjslee.config;

import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.LinkedList;
import java.util.List;

/**
 * @author fkjslee
 * @date 2018/5/5 at 21:55
 * Copyright (c) 2018 fkjslee. All rights reserved.
 */

public class MyRule extends AbstractLoadBalancerRule {

    private static final Logger log = LoggerFactory.getLogger(MyRule.class);
    private static List<MyServer> myUpList = new LinkedList<>();

    public MyRule() {
    }

    @SuppressWarnings({"RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE"})
    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            return null;
        } else {
            MyServer chooseServer = null;
            while (chooseServer == null) {
                if (Thread.interrupted()) {
                    return null;
                }

                refreshMyUpList(lb);
//                if (myUpList.size() == 0) {
//                    log.warn("the station list is empty!");
//                    return null;
//                }

                // choose min task number server
                for (MyServer myServer : myUpList) {
                    if (chooseServer == null) {
                        chooseServer = myServer;
                    } else {
                        if (myServer.taskNum < chooseServer.taskNum) {
                            chooseServer = myServer;
                        }
                    }
                }
                log.info("station choose server host and port = " + (chooseServer == null ? null : chooseServer.server.getHostPort()));
                if (chooseServer == null) {
                    Thread.yield();
                } else {
                    if (chooseServer.server.isAlive()) {
                        return chooseServer.server;
                    }
                    chooseServer = null;
                    Thread.yield();
                }
            }
            return chooseServer.server;
        }
    }

    private void refreshMyUpList(ILoadBalancer lb) {
        synchronized (myUpList) {
            myUpList.clear();
            // load stations' remain task number
            if (lb == null) return;
            log.error("check refersh my up list, size = {}", lb.getReachableServers().size());
            for (Server s : lb.getReachableServers()) {
                log.error("check refersh my up list, alive = {}", s.isAlive());
                log.error("check {}", new LoadBalancerStats("myLoadBlanced").getSingleServerStat(s));
                if (!s.isAlive()) continue;
                MyServer myServer = new MyServer(s);
//                myServer.taskNum = Integer.valueOf(HttpThread.setParamAndRun("http://" + s.getHostPort() + "/getTaskNum", "", true, "server ask for taskNum MyRule"));
                myServer.taskNum = 0;
                myUpList.add(myServer);
            }
        }
    }

    public void refreshMyUpList() {
        refreshMyUpList(this.getLoadBalancer());
        new BestAvailableRule();
    }

    public static List<MyServer> getMyUpList() {
        return myUpList;
    }

    public Server choose(Object key) {
        return this.choose(this.getLoadBalancer(), key);
    }

    public void initWithNiwsConfig(IClientConfig clientConfig) {
    }

    public class MyServer {
        private Server server;
        private Integer taskNum;
        private MyServer(Server server) {
            this.server = server;
        }

        public Server getServer() {
            return server;
        }

        public Integer getTaskNum() {
            return taskNum;
        }
    }
}
